package org.ztr.yanai.blog.aspect;

import cn.hutool.json.JSONUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.ztr.yanai.blog.utils.IpUtil;

/**
 * @Author: ZhaoTR
 * @Date: Created in 2025/11/22 14:30
 * @Description: 操作日志切面，记录Controller层的所有操作
 * @Version: 1.0
 */
@Slf4j
@Aspect
@Component
public class LogAspect {

    /**
     * 定义切点：拦截所有Controller
     */
    @Pointcut("execution(* org.ztr.yanai.blog.controller..*(..))")
    public void controllerPointcut() {
    }

    /**
     * 前置通知：记录请求信息
     */
    @Before("controllerPointcut()")
    public void doBefore(JoinPoint joinPoint) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            return;
        }
        
        HttpServletRequest request = attributes.getRequest();
        
        // 记录请求信息
        log.info("========== 请求开始 ==========");
        log.info("请求URL: {}", request.getRequestURL());
        log.info("请求方法: {}", request.getMethod());
        log.info("请求IP: {}", IpUtil.getClientIp(request));
        log.info("调用方法: {}.{}", 
                joinPoint.getSignature().getDeclaringTypeName(),
                joinPoint.getSignature().getName());
        
        // 记录请求参数
        Object[] args = joinPoint.getArgs();
        if (args != null && args.length > 0) {
            try {
                log.info("请求参数: {}", JSONUtil.toJsonStr(args));
            } catch (Exception e) {
                log.info("请求参数: [复杂对象，无法序列化]");
            }
        }
    }

    /**
     * 环绕通知：记录执行时间
     */
    @Around("controllerPointcut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        
        Object result = joinPoint.proceed();
        
        long endTime = System.currentTimeMillis();
        log.info("执行耗时: {} ms", (endTime - startTime));
        
        return result;
    }

    /**
     * 返回通知：记录返回结果
     */
    @AfterReturning(pointcut = "controllerPointcut()", returning = "result")
    public void doAfterReturning(Object result) {
        try {
            log.info("返回结果: {}", JSONUtil.toJsonStr(result));
        } catch (Exception e) {
            log.info("返回结果: [复杂对象，无法序列化]");
        }
        log.info("========== 请求结束 ==========\n");
    }

    /**
     * 异常通知：记录异常信息
     */
    @AfterThrowing(pointcut = "controllerPointcut()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
        log.error("========== 请求异常 ==========");
        log.error("异常方法: {}.{}", 
                joinPoint.getSignature().getDeclaringTypeName(),
                joinPoint.getSignature().getName());
        log.error("异常信息: ", e);
        log.error("========== 异常结束 ==========\n");
    }
}
